﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using NUnit.Framework;

namespace Cloak.Reflection
{
	[TestFixture]
	public class InvokeFixture
	{
		[Test]
		public void Tree()
		{
			Assert.AreEqual(
				2,
				Invoke.Tree<int>(Expression.Add(Expression.Constant(1), Expression.Constant(1))));
		}

		#region Static
		[Test]
		public void StaticField()
		{
			Assert.AreEqual(
				0,
				Invoke.Member<int>(Reflect.Field<int>(() => Target.StaticField)));
		}

		[Test]
		public void StaticProperty()
		{
			Assert.AreEqual(
				0,
				Invoke.Member<int>(Reflect.Property<int>(() => Target.StaticProperty)));
		}

		[Test]
		public void StaticMethod0Args()
		{
			Assert.AreEqual(
				0,
				Invoke.Func<int>(Reflect.Func<int>(Target.StaticFunc0Args)));
		}

		[Test]
		public void StaticMethod1Arg()
		{
			Assert.AreEqual(
				1,
				Invoke.Func<int>(
					Reflect.Func<int, int>(Target.StaticFunc1Arg),
					1));
		}

		[Test]
		public void StaticMethod2Args()
		{
			Assert.AreEqual(
				2,
				Invoke.Func<int>(
					Reflect.Func<int, int, int>(Target.StaticFunc2Args),
					1,
					1));
		}

		[Test]
		public void StaticMethod3Args()
		{
			Assert.AreEqual(
				3,
				Invoke.Func<int>(
					Reflect.Func<int, int, int, int>(Target.StaticFunc3Args),
					1,
					1,
					1));
		}

		[Test]
		public void StaticMethod4Args()
		{
			Assert.AreEqual(
				4,
				Invoke.Func<int>(
					Reflect.Func<int, int, int, int, int>(Target.StaticFunc4Args),
					1,
					1,
					1,
					1));
		}
		#endregion

		#region Instance
		[Test]
		public void Field()
		{
			var target = new Target();

			Assert.AreEqual(
				0,
				Invoke.Member<int>(
					target,
					Reflect.Field<int>(() => target.Field)));
		}

		[Test]
		public void Property()
		{
			var target = new Target();

			Assert.AreEqual(
				0,
				Invoke.Member<int>(
					target,
					Reflect.Property<int>(() => target.Property)));
		}

		[Test]
		public void Method0Args()
		{
			var target = new Target();

			Assert.AreEqual(
				0,
				Invoke.Func<int>(
					target,
					Reflect.Func<int>(target.Func0Args)));
		}

		[Test]
		public void Method1Arg()
		{
			var target = new Target();

			Assert.AreEqual(
				1,
				Invoke.Func<int>(
					target,
					Reflect.Func<int, int>(target.Func1Arg),
					1));
		}

		[Test]
		public void Method2Args()
		{
			var target = new Target();

			Assert.AreEqual(
				2,
				Invoke.Func<int>(
					target,
					Reflect.Func<int, int, int>(target.Func2Args),
					1,
					1));
		}

		[Test]
		public void Method3Args()
		{
			var target = new Target();

			Assert.AreEqual(
				3,
				Invoke.Func<int>(
					target,
					Reflect.Func<int, int, int, int>(target.Func3Args),
					1,
					1,
					1));
		}

		[Test]
		public void Method4Args()
		{
			var target = new Target();

			Assert.AreEqual(
				4,
				Invoke.Func<int>(
					target,
					Reflect.Func<int, int, int, int, int>(target.Func4Args),
					1,
					1,
					1,
					1));
		}
		#endregion

		#region Constructor
		[Test]
		public void Constructor0Args()
		{
			var constructor = Reflect.Constructor(() => new Target());

			var target = Invoke.Constructor<Target>(constructor);

			Assert.AreEqual(0, target.Property);
		}

		[Test]
		public void Constructor1Arg()
		{
			var constructor = Reflect.Constructor((int a) => new Target(a));

			var target = Invoke.Constructor<Target>(constructor, 1);

			Assert.AreEqual(1, target.Property);
		}

		[Test]
		public void Constructor2Args()
		{
			var constructor = Reflect.Constructor((int a, int b) => new Target(a, b));

			var target = Invoke.Constructor<Target>(constructor, 1, 1);

			Assert.AreEqual(2, target.Property);
		}

		[Test]
		public void Constructor3Args()
		{
			var constructor = Reflect.Constructor((int a, int b, int c) => new Target(a, b, c));

			var target = Invoke.Constructor<Target>(constructor, 1, 1, 1);

			Assert.AreEqual(3, target.Property);
		}

		[Test]
		public void Constructor4Args()
		{
			var constructor = Reflect.Constructor((int a, int b, int c, int d) => new Target(a, b, c, d));

			var target = Invoke.Constructor<Target>(constructor, 1, 1, 1, 1);

			Assert.AreEqual(4, target.Property);
		}
		#endregion
	}
}